
namespace TiledMap {

	declare interface TileMapImageLoader {
		showAsyncByCrossUrl(image: egret.DisplayObjectContainer, url: string, x?: number, y?: number, w?: number, h?: number)
	}
	export class Point {
		public x: number;
		public y: number;
		constructor(x, y) {
			this.x = x;
			this.y = y;
		}
		public update(x, y) {
			this.x = x;
			this.y = y;
		}
	}
	export class Rect {
		public x: number;
		public y: number;
		public w: number;
		public h: number;
		constructor(x, y, w, h) {
			this.x = x;
			this.y = y;
			this.w = w;
			this.h = h;
		}
	}


	export class TileMap {
		public name: string;
		/**
		 * 单个坐标点的贴图宽度
		 */
		public tilewidth: number;
		/**
		 * 单个坐标点的贴图高度
		 */
		public tileheight: number;
		/**
		 * 地图宽度,横向tile个数
		 */
		public width: number;
		/**
		 * 地图高度 纵向tile个数
		 */
		public height: number;
		public orientation: string;
		public version: string;
		public renderorder: string;
		public nextobjectid: number;

		public layers: TileLayer[] = [];
		public tilesets: TileSet[] = [];

		/**
		 * .tmx文件相对根目录的相对路径,用于http下载
		 */
		public baseURL: string;

		/**
		 * .tmx中内容. xml对象
		 */
		// private xml: egret.XML;

		public constructor(tmxFileName, baseURL) {
			this.name = tmxFileName;
			this.baseURL = baseURL;

		}
		public getImageByID(dataID: number): TileImage {
			for (var i = 0; i < this.tilesets.length; i++) {
				if (dataID >= this.tilesets[i].firstgid && dataID <= this.tilesets[i].lastgid) {
					var tileArray = this.tilesets[i].tileArr;
					var firstgid = this.tilesets[i].firstgid;
					return tileArray[Math.max(dataID - firstgid, 0)].image;//-1 for that the firstgid is increase base on 1
				}
			}
			return null;
		}
		/**
		 * 下载并解析.tmx,包括对 tileset,layer 的解析
		 */
		private loadAndParseTmx(tmx: egret.XML, callback?: Function) {
			var tileParseTask = [];
			var total = 0;
			var loadTilesProgressCallBack = function () {
				total = total > tileParseTask.length ? total : tileParseTask.length
				tileParseTask.pop();
				callback(this, total - tileParseTask.length, total);
			}.bind(this);
			for (var i = 0; i < tmx.children.length; i++) {
				var node: any = tmx.children[i];
				if (node.name == "layer") {
					this.layers.push(TileLayer.creatByTiledMap(this, node));
				} else if (node.name == "tileset") {
					this.tilesets.push(TileSet.creatByTiledMap(this, node, loadTilesProgressCallBack));
					tileParseTask.push(0);
				}


			}
		}
		/**
		 * 下载并解析.tmx文件.
		 */
		public static createTileMap(tmxFileName, baseURL, callback?: Function): void {
			FileLoader.loadXML(baseURL + tmxFileName, function (xml: egret.XML) {
				var tilemap: TileMap = new TileMap(tmxFileName, baseURL);
				tilemap.tilewidth = (<any>xml).$tilewidth;
				tilemap.tileheight = (<any>xml).$tileheight;
				tilemap.width = (<any>xml).$width;
				tilemap.height = (<any>xml).$height;
				tilemap.loadAndParseTmx(xml, function (a1, a2, a3) {
					callback(tilemap, a2, a3);
				});
			}.bind(this));
		}

		private static getRenderImageArr(map: TileMap, renderRect: Rect, dataArr: any[]): Array<any> {
			var renderImageArr = [];

			for (var i = 0; i < renderRect.w; i++) {
				renderImageArr[i] = [];
				for (var j = 0; j < renderRect.h; j++) {
					var index = (renderRect.y + j) * map.width + renderRect.x + i;
					var id = Number(dataArr[index]);
					var image: TileImage = map.getImageByID(id);
					if (image) {
						image.x = i;
						image.y = j;
						// console.log('[INFO] renderImageArr  index:' + index + " id:" + id + ":" + JSON.stringify(image));
						renderImageArr[i][j] = image;
					} else if (0 == id) {

					} else {
						console.log('[WARN] renderImageArr not find the image by  index:' + index + " id:" + id);
					}

				}
			}
			return renderImageArr;
		}
		public static renderImageArray(renderImageArr, mapLayer: egret.DisplayObjectContainer, thirdImageLoader?: TileMapImageLoader) {
			mapLayer.removeChildren();
			for (var i = 0; i < renderImageArr.length; i++) {
				for (var j = 0; j < renderImageArr[i].length; j++) {
					var image: TileImage = renderImageArr[i][j];
					if (image) {
						if (thirdImageLoader) {
							thirdImageLoader.showAsyncByCrossUrl(mapLayer, image.source, (i * 48) - image.width + 48, (j * 32) - image.height + 32, image.width, image.height);
						} else {
							
							ImageLoader.showAsyncByCrossUrl(mapLayer, "http://49.234.50.171:8888/" + image.source, (i * 48) - image.width + 48, (j * 32) - image.height + 32, image.width, image.height);
						}
					}
				}
			}
		}
		private static limitCoordInMap(x, viewMax, max) {
			var ox = Math.floor(x - viewMax / 2);
			if (ox < 0) {
				ox = 0;
			}
			if (ox > max - viewMax) {
				ox = max - viewMax;
			}
			return ox;
		}
		private static caluRenderOriginCoord(x, y, renderW, renderH, maxX, maxY): Point {
			return new Point(
				TileMap.limitCoordInMap(x, renderW, maxX),
				TileMap.limitCoordInMap(y, renderH, maxY));
		}
		public static render(map: TileMap, renderContainer: egret.DisplayObjectContainer, x, y, renderW, renderH, imageLoader?: TileMapImageLoader) {
			console.log('[INFO] orgin coord: %s,%s', x, y);
			var rxmax = Math.floor(renderW / map.tilewidth);
			var rymax = Math.floor(renderH / map.tileheight);
			var orgin = TileMap.caluRenderOriginCoord(x, y, rxmax, rymax, map.width, map.height);
			var renderRect = new Rect(
				orgin.x,
				orgin.y,
				rxmax * 2,
				rymax * 2,
			)
			console.log('[INFO] renderRect :' + JSON.stringify(renderRect));
			for (var i = 0; i < map.layers.length; i++) {
				var layer: TileLayer = map.layers[i];
				// if (layer.name != "base") {
				//     continue;
				// }
				if (layer.data.dataArr) {
					var dataArr = layer.data.dataArr;
					// console.log('[INFO] render layer: ' + layer.name );
					var renderImageArr = TileMap.getRenderImageArr(map, renderRect, dataArr);//一维数组转二纬数组
					var layer1 =<egret.DisplayObjectContainer> renderContainer.getChildByName(layer.name);
					if(!layer1){
						layer1 = new egret.DisplayObjectContainer();
						layer1.name = layer.name;
						renderContainer.addChild(layer1);
					}
					TileMap.renderImageArray(renderImageArr, layer1, imageLoader);
				} else {
					console.warn('[WARN] Not Supper DataFormat: ' + layer.data.encoding);
				}
			}
		}

	}
}